﻿using KAKA.Domain;
using KAKA.Models;
using KAKA.Repository;
using Morus;
using System;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using System.Drawing;
using System.Drawing.Imaging;
using MvcContrib;
using KAKA.Infrastructure;
using System.Text.RegularExpressions;

namespace KAKA.Controllers
{
    public class EventController : BaseController
    {
        public EventController()
            : base()
        {
            EventRepository = IoC.Resolve<IEventRepository>();
            CategoryRepository = IoC.Resolve<ICategoryRepository>();
            MemberRepository = IoC.Resolve<IMemberRepository>();
        }

        public IEventRepository EventRepository { get; private set; }
        public ICategoryRepository CategoryRepository { get; private set; }
        public IMemberRepository MemberRepository { get; private set; }

        [Authorization]
        public ActionResult Detail(string id)
        {
            if (id.IsEmpty())
            {
                return this.RedirectToAction(r => r.Index());
            }

            var evnt = EventRepository.Get(id.ToGuid());
            if (evnt != null)
            {
                if (evnt.Status == EventStatus.Closed)
                {
                    return this.RedirectToAction(r => r.Retrospect(id));
                }
            }
            else
            {
                return this.RedirectToAction(r => r.Index());
            }

            ViewBag.User = CurrentUser;

            var model = new EventModel()
            {
                Id = evnt.Id.Shrink(),
                Title = evnt.Title,
                Description = evnt.Description,
                Category = evnt.Category.Name,
                ActAt = evnt.ActAt.ToString("yyyy-MM-dd"),
                Locale = evnt.Locale,
                Audience = evnt.Audience,
                Remark = evnt.Remark,
                Status = evnt.Status,
                Charge = evnt.Charge,
                Signed = evnt.Slates.Any(r => r.Member.Id == CurrentUser.Id),
                Cover = evnt.Cover,
                IsClosed = evnt.IsClosed,
                IsHidden = evnt.IsHidden,
            };

            return View(model);
        }

        [Authorization]
        [MobileVerification]
        [ActionName("Detail")]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SignUp(string id)
        {
            try
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var evnt = EventRepository.Get(id.ToGuid());
                    var member = MemberRepository.Get(CurrentUser.Id);

                    evnt.SignUp(member);

                    uow.Commit();
                }
                return this.RedirectToAction(r => r.SignUpSuccess());
            }
            catch
            {
                return View("Detail", id);
            }
        }

        [Authorization]
        public ActionResult SignUpSuccess()
        {
            return View();
        }

        public ActionResult Retrospect(string id)
        {
            ViewBag.User = CurrentUser;

            var evnt = EventRepository.Get(id.ToGuid());
            if (evnt != null)
            {
                var model = new EventRetrospectModel()
                {
                    Id = evnt.Id.Shrink(),
                    Title = evnt.Title,
                    RetrospectHTML = evnt.RetrospectHTML,
                    IsClosed = evnt.IsClosed,
                    IsHidden = evnt.IsHidden
                };

                model.Photographs = evnt.EventPhotographs
                    .ToList()
                    .Select(r => new EventPhotographModel
                    {
                        Id = r.Id.Shrink(),
                        Caption = r.Caption,
                        Path = r.Url,
                    }).ToList();

                return View(model);
            }
            else
            {
                return this.RedirectToAction(r => r.Index());
            }
        }

        [Administration]
        public ActionResult EditRetrospect(string id)
        {
            ViewBag.User = CurrentUser;

            var evnt = EventRepository.Get(id.ToGuid());
            if (evnt != null)
            {
                var model = new EventEditRetrospectModel()
                {
                    Id = evnt.Id.Shrink(),
                    Title = evnt.Title,
                    Retrospect = evnt.Retrospect,
                };

                model.Photographs = evnt.EventPhotographs
                    .ToList()
                    .Select(r => new EventPhotographModel
                    {
                        Id = r.Id.Shrink(),
                        Caption = r.Caption,
                        Path = r.Url,
                    }).ToList();

                return View(model);
            }
            else
            {
                return this.RedirectToAction(r => r.Index());
            }
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Post)]
        [ValidateInput(false)]
        public ActionResult EditRetrospect(EventEditRetrospectModel model)
        {
            ViewBag.User = CurrentUser;

            var evnt = EventRepository.Get(model.Id.ToGuid());

            var regex = new Regex(@"\[img](http://.+\.jpg)\[/img]");
            var html = regex.Replace(model.Retrospect, new MatchEvaluator((Match m) =>
            {
                return "<img src='{0}' />".FormatWith(m.Groups[1].Value);
            }));

            if (Request.Files[0].ContentLength > 0)
            {
                var fileId = Guid.NewGuid().Shrink();
                var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Event", evnt.Id.Shrink());
                var photoPath = Path.Combine(directory, fileId + ".jpg");

                using (Bitmap bitmap = new Bitmap(Request.Files[0].InputStream))
                using (MemoryStream ms = new MemoryStream())
                {
                    bitmap.Save(ms, ImageFormat.Jpeg);
                    ms.Flush();

                    var buff = ms.GetBuffer();
                    Util.Image.Save(buff, photoPath);
                }

                using (var uow = UnitOfWork.Begin())
                {
                    var photograph = new EventPhotograph()
                    {
                        Id = Guid.NewGuid(),
                        CreateAt = DateTime.Now,
                        Url = fileId,
                        Caption = model.Caption ?? evnt.Title,
                        Event = evnt,
                    };

                    evnt.Retrospect = model.Retrospect;
                    evnt.RetrospectHTML = html;
                    evnt.EventPhotographs.Add(photograph);

                    uow.Commit();
                }

                return EditRetrospect(model.Id);
            }
            else
            {
                using (var uow = UnitOfWork.Begin())
                {
                    evnt.Retrospect = model.Retrospect;
                    evnt.RetrospectHTML = html;

                    uow.Commit();
                }
            }

            return EditRetrospect(model.Id);
        }

        public ActionResult Last()
        {
            ViewBag.User = CurrentUser;

            var last = EventRepository.GetAll()
                .ToList()
                .Where(r => !r.IsHidden)
                .OrderByDescending(r => r.ActAt)
                .FirstOrDefault();

            if (last != null)
            {
                return this.RedirectToAction(r => r.Detail(last.Id.Shrink()));
            }
            else
            {
                return this.RedirectToAction(r => r.Index());
            }
        }

        public ActionResult Index()
        {
            var model = EventRepository.GetAll()
                .ToList()
                .Select(r =>
                    new EventModel
                    {
                        Id = r.Id.Shrink(),
                        Title = r.Title,
                        Description = r.Description,
                        Category = r.Category.Name,
                        ActAt = r.ActAt.ToString("yyyy-MM-dd"),
                        Locale = r.Locale,
                        Audience = r.Audience,
                        Remark = r.Remark,
                        Charge = r.Charge,
                        Cover = r.Cover,
                        SlateAmount = r.Slates.Count,
                        Status = r.Status,
                        IsClosed = r.IsClosed,
                        IsHidden = r.IsHidden
                    });

            ViewBag.User = CurrentUser;

            return View(model);
        }

        [Administration]
        public ActionResult Add()
        {
            ViewBag.Category = CategoryRepository.GetAll()
                .ToArray()
                .Select(r => new SelectListItem
                {
                    Text = r.Name,
                    Value = r.Id.Shrink()
                });

            ViewBag.User = CurrentUser;

            return View();
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Add(EventModel model)
        {
            try
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var evnt = Event.Create();

                    evnt.Title = model.Title;
                    evnt.Description = model.Description;
                    evnt.Category = CategoryRepository.Get(model.Category.ToGuid());
                    evnt.ActAt = DateTime.Parse(model.ActAt);
                    evnt.Locale = model.Locale;
                    evnt.Audience = model.Audience;
                    evnt.Remark = model.Remark;
                    evnt.Visits = 0;
                    evnt.Charge = model.Charge;
                    evnt.User = CurrentUser;

                    EventRepository.Add(evnt);

                    uow.Commit();

                    return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
                }
            }
            catch
            {
                return View();
            }
        }

        [Administration]
        public ActionResult Edit(string id)
        {
            var evnt = EventRepository.Get(id.ToGuid());
            var model = new EventModel()
            {
                Id = evnt.Id.Shrink(),
                Title = evnt.Title,
                Description = evnt.Description,
                Category = evnt.Category.Id.Shrink(),
                ActAt = evnt.ActAt.ToString("yyyy-MM-dd"),
                Locale = evnt.Locale,
                Audience = evnt.Audience,
                Remark = evnt.Remark,
                Charge = evnt.Charge,
            };

            var categories = CategoryRepository.GetAll()
                .ToList()
                .Select(r => new SelectListItem()
                {
                    Text = r.Name,
                    Value = r.Id.Shrink(),
                })
                .ToList();
            categories.FindAll(r => r.Value == model.Category)
                .ForEach(r =>
                {
                    r.Selected = true;
                });

            ViewBag.Category = categories;
            ViewBag.User = CurrentUser;

            return View("Add", model);
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(EventModel model)
        {
            ViewBag.User = CurrentUser;

            try
            {
                using (var uow = UnitOfWork.Begin())
                {
                    var evnt = EventRepository.Get(model.Id.ToGuid());

                    evnt.Title = model.Title;
                    evnt.Description = model.Description;
                    evnt.Category = CategoryRepository.Get(model.Category.ToGuid());
                    evnt.ActAt = DateTime.Parse(model.ActAt);
                    evnt.Locale = model.Locale;
                    evnt.Audience = model.Audience;
                    evnt.Remark = model.Remark;
                    evnt.Charge = model.Charge;
                    evnt.User = CurrentUser;

                    uow.Commit();

                    return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
                }
            }
            catch
            {
                return Edit(model.Id);
            }
        }

        [Administration]
        public ActionResult Activate(string id)
        {
            using (var uow = UnitOfWork.Begin())
            {
                var evnt = EventRepository.Get(id.ToGuid());
                evnt.Activate();

                uow.Commit();

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }
        }

        [Administration]
        public ActionResult Hide(string id)
        {
            using (var uow = UnitOfWork.Begin())
            {
                var evnt = EventRepository.Get(id.ToGuid());
                evnt.Hide();

                uow.Commit();

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }
        }

        [Administration]
        public ActionResult Show(string id)
        {
            using (var uow = UnitOfWork.Begin())
            {
                var evnt = EventRepository.Get(id.ToGuid());
                evnt.Show();

                uow.Commit();

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }
        }

        [Administration]
        public ActionResult Close(string id)
        {
            using (var uow = UnitOfWork.Begin())
            {
                var evnt = EventRepository.Get(id.ToGuid());
                evnt.Close();

                uow.Commit();

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }
        }

        [Administration]
        public ActionResult Delete(string id)
        {
            using (var uow = UnitOfWork.Begin())
            {
                var evnt = EventRepository.Get(id.ToGuid());
                evnt.Delete();

                uow.Commit();

                return this.RedirectToAction(r => r.Index());
            }
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Get)]
        public ActionResult UploadCover(string id)
        {
            var evnt = EventRepository.Get(id.ToGuid());
            var model = new EventCoverModel()
            {
                CoverPath = evnt.Cover,
                Id = evnt.Id.Shrink()
            };

            ViewBag.User = CurrentUser;

            return View(model);
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult UploadCover(EventCoverModel model)
        {
            if (Request.Files[0].ContentLength > 0)
            {
                var evnt = EventRepository.Get(model.Id.ToGuid());

                var fileId = Guid.NewGuid().Shrink();
                var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Event", evnt.Id.Shrink());
                var coverPath = Path.Combine(directory, fileId + ".jpg");
                var microPath = Path.Combine(directory, fileId + "-micro.jpg");

                using (Bitmap bitmap = new Bitmap(Request.Files[0].InputStream))
                using (MemoryStream ms = new MemoryStream())
                {
                    bitmap.Save(ms, ImageFormat.Jpeg);
                    ms.Flush();

                    var buff = ms.GetBuffer();
                    Util.Image.Save(buff, coverPath);

                    var micro = Util.Image.Resize(buff, bitmap.Width / 3, bitmap.Height / 3);
                    Util.Image.Save(micro, microPath);
                }

                using (var uow = UnitOfWork.Begin())
                {
                    evnt.Cover = fileId;
                    uow.Commit();
                }

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }

            return UploadCover(model.Id);
        }

        [Administration]
        public ActionResult UploadPhotograph(string id)
        {
            var evnt = EventRepository.Get(id.ToGuid());
            var model = new EventPhotographModel()
            {
                Id = evnt.Id.Shrink()
            };

            ViewBag.User = CurrentUser;

            return View(model);
        }

        [Administration]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult UploadPhotograph(EventPhotographModel model)
        {
            ViewBag.User = CurrentUser;

            if (Request.Files.Count > 0)
            {
                var evnt = EventRepository.Get(model.Id.ToGuid());

                var fileId = Guid.NewGuid().Shrink();
                var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets", "Event", evnt.Id.Shrink());
                var photoPath = Path.Combine(directory, fileId + ".jpg");

                using (Bitmap bitmap = new Bitmap(Request.Files[0].InputStream))
                using (MemoryStream ms = new MemoryStream())
                {
                    bitmap.Save(ms, ImageFormat.Jpeg);
                    ms.Flush();

                    var buff = ms.GetBuffer();
                    Util.Image.Save(buff, photoPath);
                }

                using (var uow = UnitOfWork.Begin())
                {
                    var photograph = new EventPhotograph()
                    {
                        Id = Guid.NewGuid(),
                        CreateAt = DateTime.Now,
                        Url = fileId,
                        Caption = model.Caption,
                        Event = evnt,
                    };

                    evnt.EventPhotographs.Add(photograph);

                    uow.Commit();
                }

                return this.RedirectToAction(r => r.Detail(evnt.Id.Shrink()));
            }

            return UploadPhotograph(model.Id);
        }

        [Administration]
        public ActionResult Slate(string id)
        {
            var evnt = EventRepository.Get(id.ToGuid());
            var model = new EventSlateModel()
            {
                Id = evnt.Id.Shrink(),
                Name = evnt.Title,
                Members = evnt.Slates.Select(r => new EventSlateMemberModel
                {
                    Id = r.Member.Id.Shrink(),
                    Name = r.Member.Nickname,
                    Charge = r.Charge,
                    Paid = r.Paid
                }).ToArray()
            };

            ViewBag.User = CurrentUser;

            return View(model);
        }
    }
}
